/*
 * @Author: your name
 * @Date: 2021-05-08 15:23:41
 * @LastEditTime: 2021-05-08 16:13:18
 * @LastEditors: Please set LastEditors
 * @Description: 这个文件包含一些通用工具，包括 move, forward, swap 等函数，以及 pair 等 
 * @FilePath: /mei/project/MySTL/STL/util.h
 */
#ifndef MYSTL_UTIL_H
#define MYSTL_UTIL_H

#include <cstddef>
#include <iostream>
#include "type_traits.h"

namespace mystl {
    //move
    template<class T>
    typename std::remove_reference<T>::type &&move(T &&arg) noexcept {
        return static_cast<typename std::remove_reference<T>::type &&>(arg);
    }

    //forward 一般转发是将右值参数继续以右值的方式的传递
    template<class T>
    T &&forward(typename std::remove_reference<T>::type &arg) noexcept {
        return static_cast<T &&>(arg);
    }

    template<class T>
    T &&forward(typename std::remove_reference<T>::type &&arg)noexcept {
        static_assert(!std::is_lvalue_reference<T>::value, "bad forward");
        return static_cast<T &&>(arg);
    }

    //swap
    template<class Tp>
    void swap(Tp &ls, Tp &rs) {
        auto tmp(mystl::move(ls));
        ls = mystl::move(rs);
        rs = mystl::move(tmp);
    }

    template<class ForwardIter1, class ForwardIter2>
    ForwardIter2 swap_range(ForwardIter1 first1, ForwardIter1 end1, ForwardIter2 first2) {
        for (; first1 != end1; ++first1, ++first2) {
            mystl::swap(*first1, *first2);
        }
        return first2;
    };

    template<class Tp, size_t N>
    void swap(Tp (&a)[N], Tp (&b)[N]) { //交换数组
        mystl::swap_range(a, a + N, b);
    };

    //pair 结构体模板
    //first 代表第一个数据   second 代表第二个数据
    template<class Ty1, class Ty2>
    struct pair {
        typedef Ty1 first_type;
        typedef Ty2 second_type;
        first_type first;
        second_type second;

        //默认的构造函数
        template<class Other1 = Ty1, class Other2=Ty2,
                typename = typename std::enable_if<
                        std::is_default_constructible<Other1>::value &&
                        std::is_default_constructible<Other2>::value, void>::type>
        constexpr pair():first(), second() {};

        template<class U1 = Ty1, class U2 = Ty2,
                typename std::enable_if<
                        std::is_copy_constructible<U1>::value &&
                        std::is_copy_constructible<U2>::value &&
                        std::is_convertible<const U1 &, Ty1>::value &&
                        std::is_convertible<const U2 &, Ty2>::value, int>::type = 0>
        constexpr pair(const Ty1 &a, const Ty2 &b)
                : first(a), second(b) {
        }

        template<class U1 = Ty1, class U2 = Ty2,
                typename std::enable_if<
                        std::is_copy_constructible<U1>::value &&
                        std::is_copy_constructible<U2>::value &&
                        (!std::is_convertible<const U1 &, Ty1>::value ||
                         !std::is_convertible<const U2 &, Ty2>::value), int>::type = 0>
        explicit constexpr pair(const Ty1 &a, const Ty2 &b)
                : first(a), second(b) {
        }

        pair(const pair &rhs) = default;

        pair(pair &rhs) = default;

        // implicit constructiable for other type
        template<class Other1, class Other2,
                typename std::enable_if<
                        std::is_constructible<Ty1, Other1>::value &&
                        std::is_constructible<Ty2, Other2>::value &&
                        std::is_convertible<Other1 &&, Ty1>::value &&
                        std::is_convertible<Other2 &&, Ty2>::value, int>::type = 0>
        constexpr pair(Other1 &&a, Other2 &&b)
                : first(mystl::forward<Other1>(a)),
                  second(mystl::forward<Other2>(b)) {
        }

        // explicit constructiable for other type
        template<class Other1, class Other2,
                typename std::enable_if<
                        std::is_constructible<Ty1, Other1>::value &&
                        std::is_constructible<Ty2, Other2>::value &&
                        (!std::is_convertible<Other1, Ty1>::value ||
                         !std::is_convertible<Other2, Ty2>::value), int>::type = 0>
        explicit constexpr pair(Other1 &&a, Other2 &&b)
                : first(mystl::forward<Other1>(a)),
                  second(mystl::forward<Other2>(b)) {
        }

        // implicit constructiable for other pair
        template<class Other1, class Other2,
                typename std::enable_if<
                        std::is_constructible<Ty1, const Other1 &>::value &&
                        std::is_constructible<Ty2, const Other2 &>::value &&
                        std::is_convertible<const Other1 &, Ty1>::value &&
                        std::is_convertible<const Other2 &, Ty2>::value, int>::type = 0>
        constexpr pair(const pair<Other1, Other2> &other)
                : first(other.first),
                  second(other.second) {
        }

        // explicit constructiable for other pair
        template<class Other1, class Other2,
                typename std::enable_if<
                        std::is_constructible<Ty1, const Other1 &>::value &&
                        std::is_constructible<Ty2, const Other2 &>::value &&
                        (!std::is_convertible<const Other1 &, Ty1>::value ||
                         !std::is_convertible<const Other2 &, Ty2>::value), int>::type = 0>
        explicit constexpr pair(const pair<Other1, Other2> &other)
                : first(other.first),
                  second(other.second) {
        }

        // implicit constructiable for other pair
        template<class Other1, class Other2,
                typename std::enable_if<
                        std::is_constructible<Ty1, Other1>::value &&
                        std::is_constructible<Ty2, Other2>::value &&
                        std::is_convertible<Other1, Ty1>::value &&
                        std::is_convertible<Other2, Ty2>::value, int>::type = 0>
        constexpr pair(pair<Other1, Other2> &&other)
                : first(mystl::forward<Other1>(other.first)),
                  second(mystl::forward<Other2>(other.second)) {
        }

        // explicit constructiable for other pair
        template<class Other1, class Other2,
                typename std::enable_if<
                        std::is_constructible<Ty1, Other1>::value &&
                        std::is_constructible<Ty2, Other2>::value &&
                        (!std::is_convertible<Other1, Ty1>::value ||
                         !std::is_convertible<Other2, Ty2>::value), int>::type = 0>
        explicit constexpr pair(pair<Other1, Other2> &&other)
                : first(mystl::forward<Other1>(other.first)),
                  second(mystl::forward<Other2>(other.second)) {
        }

        // copy assign for this pair
        pair &operator=(const pair &rhs) {
            if (this != &rhs) {
                first = rhs.first;
                second = rhs.second;
            }
            return *this;
        }

        // move assign for this pair
        pair &operator=(pair &&rhs) {
            if (this != &rhs) {
                first = mystl::move(rhs.first);
                second = mystl::move(rhs.second);
            }
            return *this;
        }

        // copy assign for other pair
        template<class Other1, class Other2>
        pair &operator=(const pair<Other1, Other2> &other) {
            first = other.first;
            second = other.second;
            return *this;
        }

        // move assign for other pair
        template<class Other1, class Other2>
        pair &operator=(pair<Other1, Other2> &&other) {
            first = mystl::forward<Other1>(other.first);
            second = mystl::forward<Other2>(other.second);
            return *this;
        }

        ~pair() = default;

        void swap(pair &other) {
            if (this != &other) {
                mystl::swap(first, other.first);
                mystl::swap(second, other.second);
            }
        }
    };

// 重载比较操作符
    template<class Ty1, class Ty2>
    bool operator==(const pair<Ty1, Ty2> &lhs, const pair<Ty1, Ty2> &rhs) {
        return lhs.first == rhs.first && lhs.second == rhs.second;
    }

    template<class Ty1, class Ty2>
    bool operator<(const pair<Ty1, Ty2> &lhs, const pair<Ty1, Ty2> &rhs) {
        return lhs.first < rhs.first || (lhs.first == rhs.first && lhs.second < rhs.second);
    }

    template<class Ty1, class Ty2>
    bool operator!=(const pair<Ty1, Ty2> &lhs, const pair<Ty1, Ty2> &rhs) {
        return !(lhs == rhs);
    }

    template<class Ty1, class Ty2>
    bool operator>(const pair<Ty1, Ty2> &lhs, const pair<Ty1, Ty2> &rhs) {
        return rhs < lhs;
    }

    template<class Ty1, class Ty2>
    bool operator<=(const pair<Ty1, Ty2> &lhs, const pair<Ty1, Ty2> &rhs) {
        return !(rhs < lhs);
    }

    template<class Ty1, class Ty2>
    bool operator>=(const pair<Ty1, Ty2> &lhs, const pair<Ty1, Ty2> &rhs) {
        return !(lhs < rhs);
    }

    //重载 mystl 的 swap
    template<class Ty1, class Ty2>
    void swap(pair<Ty1, Ty2> &lhs, pair<Ty1, Ty2> &rhs) {
        lhs.swap(rhs);
    }

    //全局函数，让两个数据成为一个 pair
    template<class Ty1, class Ty2>
    pair<Ty1, Ty2> make_pair(Ty1 &&first, Ty2 &&second) {
        return pair<Ty1, Ty2>(mystl::forward<Ty1>(first), mystl::forward<Ty2>(second));
    }
}
#endif
